// dict.go
package main

import (
	"fmt"
	"sort"
	"strconv"
)

type DrMap struct {
	DrAbstractObject
	ISequence
	dataInt map[int]IObject
	dataStr map[string]IObject
	interp  *Interpreter
}

func (interp *Interpreter) NewMap() *DrMap {
	m := new(DrMap)
	m.dataInt = make(map[int]IObject)
	m.dataStr = make(map[string]IObject)
	m.Type = TypeMap
	m.members = make(map[string]IObject)
	m.members["keys"] = NewFunction("keys", nil)
	m.members["values"] = NewFunction("values", nil)
	m.members["has_key"] = NewFunction("has_key", []string{"key"})
	m.members["remove"] = NewFunction("remove", []string{"key"})
	m.interp = interp
	return m
}
func (self *DrMap) Len() int {
	return len(self.dataInt) + len(self.dataStr)
}
func (self *DrMap) getInnerKeys() ([]int, []string) {
	keysInt := make([]int, 0, 10)
	keysStr := make([]string, 0, 10)
	for k, _ := range self.dataInt {
		keysInt = append(keysInt, k)
	}
	sort.Ints(keysInt)
	for k, _ := range self.dataStr {
		keysStr = append(keysStr, k)
	}
	sort.Strings(keysStr)
	return keysInt, keysStr
}
func (self *DrMap) Keys() []IObject {
	keysInt, keysStr := self.getInnerKeys()
	keys := make([]IObject, 0, 50)
	for _, k := range keysInt {
		keys = append(keys, NewInt(k))
	}
	for _, s := range keysStr {
		keys = append(keys, NewStr(s))
	}
	return keys
}
func (self *DrMap) Values() []IObject {
	keysInt, keysStr := self.getInnerKeys()
	vs := make([]IObject, 0, 50)
	for _, k := range keysInt {
		vs = append(vs, self.dataInt[k])
	}
	for _, k := range keysStr {
		vs = append(vs, self.dataStr[k])
	}
	return vs
}
func (self *DrMap) HasKey(key IObject) bool {
	if key.getType() == TypeInt {
		_, ok := self.dataInt[key.getInt()]
		if ok {
			return true
		}
	}
	if key.getType() == TypeString {
		_, ok := self.dataStr[key.AsString()]
		if ok {
			return true
		}
	}

	return false
}
func (self *DrMap) SetKeyValue(key IObject, value IObject) {
	if key.getType() == TypeInt {
		self.dataInt[key.getInt()] = value
	} else if key.getType() == TypeString {
		self.dataStr[key.AsString()] = value
	} else {
		panic("not implemented for other key types")
	}
}
func (self *DrMap) removeKey(key IObject) {
	if key.getType() == TypeInt {
		delete(self.dataInt, key.getInt())
	} else if key.getType() == TypeString {
		delete(self.dataStr, key.AsString())
	} else {
		panic("not implemented for other key types")
	}
}
func (self *DrMap) getType() DataType {
	return self.Type
}
func (self *DrMap) GetValue(key IObject) IObject {
	if key.getType() == TypeInt {
		return self.dataInt[key.getInt()]
	} else if key.getType() == TypeString {
		return self.dataStr[key.AsString()]
	} else {
		panic("not implemented for other key types")
	}
}
func (self *DrMap) AsString() string {
	count := 0
	s := "map("
	for k, ob := range self.dataInt {
		s += strconv.FormatInt(int64(k), 10) + ":" + ob.AsString() + ","
		count += 1
		if count > 10 {
			s += " ... "
			break
		}
	}
	for k, ob := range self.dataStr {
		s += k + ":" + ob.AsString() + ","
		count += 1
		if count > 10 {
			s += " ... "
			break
		}
	}
	s += ")"
	return s
}
func (self *DrMap) getMembers() map[string]IObject {
	return self.members
}
func (self *DrMap) Print(interp *Interpreter) {
	fmt.Print(self.AsString())
}
func (self *DrMap) executeMethod(funcName string, prams []IObject) IObject {

	if funcName == "has_key" {
		if self.HasKey(prams[1]) {
			return self.interp.TrueObject
		} else {
			return self.interp.FalseObject
		}
	}
	if funcName == "keys" {
		return NewList(self.Keys())
	}
	if funcName == "values" {
		return NewList(self.Values())
	}
	if funcName == "remove" {
		self.removeKey(prams[1])
		return nil
	}
	panic("funcName is inexist for this object")

}
